#include "bsp_i2c.h"
#include "debug.h"

#define     delay_1ms(x)    Delay_Ms(x)

void I2C_Config(void)
{
    /* Initialize GPIO pins */
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN|I2C_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

    GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);

}

void I2C_delay(void)
{
    __IO uint32_t t = 20;

    while( t-- )
    {
        __NOP();
    }
}

int I2C_Start(void)
{

    SDA_HIGH;
    SCL_HIGH;
    I2C_delay();
    if(!SDA_READ){
        return DISABLE;
    }
    SDA_LOW;
    I2C_delay();
    if(SDA_READ){
        return DISABLE;
    }
    SCL_LOW;
    I2C_delay();
    return ENABLE;
}

void I2C_Stop(void)
{

    SCL_LOW;
    I2C_delay();
    SDA_LOW;
    I2C_delay();
    SCL_HIGH;
    I2C_delay();
    SDA_HIGH;
    I2C_delay();
}

void I2C_Ack()
{
    SCL_LOW;
    I2C_delay();
    SDA_LOW;
    I2C_delay();
    SCL_HIGH;
    I2C_delay();
    SCL_LOW;
    I2C_delay();
}

void I2C_NoAck()
{
    SCL_LOW;
    I2C_delay();
    SDA_HIGH;
    I2C_delay();
    SCL_HIGH;
    I2C_delay();
    SCL_LOW;
    I2C_delay();
}

uint8_t I2C_GetAck(void)
{
    uint8_t time = 0;

    SDA_HIGH;
    I2C_delay();
    SCL_HIGH;
    I2C_delay();
    while(SDA_READ)
    {
        time++;
        if(time > 250)
        {
            SCL_LOW;
            return DISABLE;
        }
    }
    SCL_LOW;
    return ENABLE;
}

void I2C_SendByte(uint8_t Data)
{

    for(uint8_t cnt=0; cnt<8; cnt++)
    {
        SCL_LOW;
        I2C_delay();

        if(Data & 0x80)
        {
            SDA_HIGH;
        }
        else
        {
            SDA_LOW;
        }
        Data <<= 1;
        SCL_HIGH;
        I2C_delay();
    }
    SCL_LOW;
    I2C_delay();
}

uint8_t I2C_ReadByte(uint8_t ack)
{
    uint8_t cnt;
    uint8_t data = 0;

    for(cnt=0; cnt<8; cnt++)
    {
        SCL_LOW;
        I2C_delay();

        SCL_HIGH;
        data <<= 1;
        if(SDA_READ)
        {
            data |= 0x01;
        }
        I2C_delay();
    }

    if(ack == 1)
    {
        I2C_NoAck();
    }
    else
    {
        I2C_Ack();
    }
    return data;
}

uint8_t I2C_WriteByte(uint8_t SendByte, uint8_t WriteAddress, uint8_t DeviceAddress)
{
    if(!I2C_Start())return DISABLE;
    I2C_SendByte(DeviceAddress & 0xFE); /*ÉèÖÃ¸ßÆðÊ¼µØÖ·+Æ÷¼þµØÖ· */
    if(!I2C_GetAck()){I2C_Stop(); return DISABLE;}
    I2C_SendByte(WriteAddress);   /* ÉèÖÃµÍÆðÊ¼µØÖ· */
    I2C_GetAck();
    I2C_SendByte(SendByte);
    I2C_GetAck();
    I2C_Stop();
    return ENABLE;
}

uint8_t I2C_ReadByteN(uint8_t ReadAddress,  uint8_t DeviceAddress)
{
    if(!I2C_Start())return DISABLE;
    I2C_SendByte(DeviceAddress & 0xFE);
    if(!I2C_GetAck()){I2C_Stop(); return DISABLE;}
    I2C_SendByte(ReadAddress);
    I2C_GetAck();
    I2C_Start();
    I2C_SendByte(DeviceAddress & 0xFF);
    I2C_GetAck();
    return I2C_ReadByte(1);
}

/* ?????? - ???????? */
uint8_t I2C_WriteBurst(uint8_t *SendData, uint8_t StartAddress, uint8_t DeviceAddress, uint8_t DataLength)
{
    if(!I2C_Start()) return DISABLE;

    /* ?????? + ??? */
    I2C_SendByte(DeviceAddress & 0xFE);
    if(!I2C_GetAck()) { I2C_Stop(); return DISABLE; }

    /* ????????? */
    I2C_SendByte(StartAddress);
    if(!I2C_GetAck()) { I2C_Stop(); return DISABLE; }

    /* ?????????? */
    for(uint8_t i = 0; i < DataLength; i++) {
        I2C_SendByte(SendData[i]);
        if(!I2C_GetAck()) {
            I2C_Stop();
            return DISABLE;
        }
    }

    I2C_Stop();
    return ENABLE;
}
